package cn.net.sinodata.system.msghandler.parse.scripthandler;

import cn.hutool.core.collection.CollectionUtil;
import cn.net.sinodata.system.msghandler.exception.DynamicParseException;
import cn.net.sinodata.system.msghandler.exception.ScriptExecuteException;
import groovy.lang.Script;
import lombok.extern.slf4j.Slf4j;

import java.util.HashMap;
import java.util.Map;

/**
 * 脚本解析处理器(每一个报文对应一个对象)
 */
@Slf4j
public class ScriptHandler {

    // 脚本中方法的名称（名称是统一的）
    private static final String SCRIPT_METHOD_NAME = "execute";

    // 缓存本实例中脚本执行的结果
    private Map<String, CommonScriptResult> scriptResultCacheMap = new HashMap<>();

    /**
     * 脚本执行器
     * @param parseResult
     * @param handler
     * @return
     * @throws DynamicParseException
     */
    public String caller(Object parseResult, String handler) throws ScriptExecuteException {
        long start = System.currentTimeMillis();
        try {
            String[] handlerArr = handler.split("\\.");
            if (handlerArr.length < 2) {
                throw new ScriptExecuteException("handler配置格式错，缺少属性值：" + handler);
            }

            // 判断脚本是否存在
            String scriptName = handlerArr[0];
            Script script = ScriptLoader.getScript(scriptName);
            if (script == null) {
                throw new ScriptExecuteException(scriptName + "脚本不存在");
            }

            // 判断缓存中是否存在
            CommonScriptResult scriptResult;
            if (scriptResultCacheMap.containsKey(scriptName)) {
                scriptResult = scriptResultCacheMap.get(scriptName);
            } else {
                // 执行脚本
                scriptResult = (CommonScriptResult)script.invokeMethod(SCRIPT_METHOD_NAME, new Object[]{parseResult});
                scriptResultCacheMap.put(scriptName, scriptResult);
            }

            if (scriptResult.isSuccess()) {
                Map<String, Object> dataMap = scriptResult.getData();
                if (CollectionUtil.isEmpty(dataMap)) {
                    return null;
                }
                String value = null;
                for (int i = 1; i < handlerArr.length; i++) {
                    Object tmpVal = dataMap.get(handlerArr[i]);
                    if (!(tmpVal instanceof String) && !(tmpVal instanceof Map)) {
                        throw new ScriptExecuteException(scriptName + "脚本执行结果格式不正确（多层嵌套时，map中的value类型只能是Map<String, String>或Map<String, Object>）。最终结果只允许是String类型");
                    }
                    if (i == handlerArr.length-1) {
                        value = (String) tmpVal;
                    } else {
                        dataMap = (Map<String, Object>) tmpVal;
                    }
                }
                long end = System.currentTimeMillis();
                log.info("耗时 = " + (end - start));
                return value;
            }

            if (scriptResult.isEmpty()) {
                log.info("scriptResult.getMsg() = " + scriptResult.getMsg());
                return null;
            } else {
                // 脚本执行失败
                log.info("scriptResult.getMsg() = " + scriptResult.getMsg());
                String msg = scriptResult.getMsg();
                throw new ScriptExecuteException("脚本执行失败，失败原因：" + msg);
            }
        } catch (Exception e) {
            log.error("调用Groovy脚本出错: ", e);
            throw new ScriptExecuteException("调用Groovy脚本出错: " + e.getMessage(), e);
        }
    }

}


